package com.vogue.supplymall.account.controller;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.vogue.supplymall.account.domain.bean.ConstantBean;
import com.vogue.supplymall.account.domain.bean.PropertiesConfig;
import com.vogue.supplymall.account.domain.dto.RegistDTO;
import com.vogue.supplymall.account.domain.dto.UpdatepwdDTO;
import com.vogue.supplymall.account.domain.service.UserService;
import com.vogue.supplymall.account.domain.service.impl.SpringContextUtils;
import com.vogue.supplymall.account.shiro.realm.AuthRealm;
import com.vogue.supplymall.account.shiro.realm.VerificationCodeRealm;
import com.vogue.supplymall.account.shiro.token.VerificationCodeToken;
import com.vogue.supplymall.common.domain.dto.ControllerResultInfo;
import com.vogue.supplymall.common.domain.dto.UserInfo;
import com.vogue.supplymall.common.domain.tool.MathUtils;
import com.vogue.supplymall.common.domain.tool.SMSUtils;
import com.vogue.supplymall.common.domain.tool.VestUtils;
import com.vogue.supplymall.common.domain.validate.Regex;
import com.vogue.supplymall.common.exception.NeedOnceLoginException;
import com.vogue.supplymall.common.exception.TelIsNotUsedException;
import com.vogue.supplymall.common.exception.TelRegistRepeatException;
import com.vogue.supplymall.common.exception.TooFrequentException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by 崔岳 on 2017-11-30. <br>
 * 用户注册
 */
@Validated
@RestController
public class RegistController extends BaseController {

    public static final Logger LOGGER_REGISTCONTROLLER = LoggerFactory.getLogger(RegistController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private PropertiesConfig propertiesConfig;

    /**
     * 注册开通账户
     * @param appver App版本号
     * @param dto 封装前台数据
     * @param request 请求对象
     * @return ResponseEntity<ControllerResultInfo>
     */
    @RequestMapping(value = "/ns/{appver}/account/regist", method = RequestMethod.POST)
    public ResponseEntity<ControllerResultInfo> regist(
            @PathVariable("appver") @Regex(name = "appver", regexcontent = "vernum")String appver,
            @Validated @RequestBody RegistDTO dto,
            HttpServletRequest request) {
        this.verifymsmcode(request, dto.getCheckCode());
        String code = userService.registUser(dto);
//发短信(如果发送异常需要记录下来，重复尝试发送)
        try {
            SMSUtils.sendMessage(dto.getTel(), messageSourceUtils.getMessage("regist.msm.success",
                    new Object[] {
                            VestUtils.getName(),
                            VestUtils.getName(),
                            code,
                            dto.getTel(),
                            dto.getPassword()}));
        } catch (Exception e) {
            LOGGER_REGISTCONTROLLER.error("send msm is error:" + e.toString());
        }
        ControllerResultInfo result = new ControllerResultInfo();
        result.setData(code);
        return new ResponseEntity<ControllerResultInfo>(result, HttpStatus.OK);
    }

    /**
    * 获取注册时候需要的激活码
    * @param appver App版本号
    * @param tel 发送手机号
    * @param request 请求对象
    * @return ResponseEntity<Map<String, String>>
    */
    @RequestMapping(value = "/ns/{appver}/account/registmsm/{tel}", method = RequestMethod.POST)
    public ResponseEntity<Map<String, String>> sendregistmsm(@PathVariable("appver") @Regex(name = "appver", regexcontent = "vernum")String appver,
            @PathVariable("tel") @Regex(name = "tel", regexcontent = "tel")String tel,
            HttpServletRequest request) {
        if (request.getSession().getAttribute(ConstantBean.REQ_REGISTMSM_TIME) != null) {
            //如果上一次发送的时间与现在间隔不到50秒，则抛异常告知太过频繁请等待
            if ((new Date()).getTime() - ((Date) request.getSession().getAttribute(ConstantBean.REQ_REGISTMSM_TIME)).getTime()
                    < propertiesConfig.getSendmsmInterval()) {
                throw new TooFrequentException("");
            }
        }
        long code = MathUtils.randomNumber(com.vogue.supplymall.common.constant.ConstantBean.VERIFICATION_CODE_DIGIT);
        String msm = messageSourceUtils.getMessage("regist.msm.activationcode",
                new Object[] {
                        VestUtils.getName(),
                        String.valueOf(code),
                        propertiesConfig.getActcodeEffectiveTime() / com.vogue.supplymall.common.constant.ConstantBean.ONE_MINUTE_TIME});
        try {
            SMSUtils.sendMessage(tel, msm);
        } catch (Exception e) {
            LOGGER_REGISTCONTROLLER.error("send msm is error:" + e.toString());
        }
        Map<String, java.io.Serializable> codemap = new HashMap<>();
        codemap.put(ConstantBean.REQ_VERIFYMSMCODE_CODE, String.valueOf(code));
        codemap.put(ConstantBean.REQ_VERIFYMSMCODE_TIME,  new Date());
        request.getSession().setAttribute(ConstantBean.REQ_REGISTMSM_TIME, new Date());
        request.getSession().setAttribute(ConstantBean.REQ_ACTIVATION_CODE, codemap);
        Map<String, String> map = new HashMap<String, String>();
        map.put("msm", msm);
        return new ResponseEntity<Map<String, String>>(map, HttpStatus.OK);
    }

    /**
    * 验证手机号码是否空闲可用(未被使用过)
    * @param appver 版本号
    * @param tel 手机号码
    * @param request 请求对象
    * @return ResponseEntity<ControllerResultInfo>
    */
    @RequestMapping(value = "/ns/{appver}/account/verifytelfree/{tel}", method = RequestMethod.POST)
    public ResponseEntity<ControllerResultInfo> verifyTelFree(
            @PathVariable("appver") @Regex(name = "appver", regexcontent = "vernum")String appver,
            @PathVariable("tel") @Regex(name = "tel", regexcontent = "tel")String tel,
            HttpServletRequest request) {
        boolean flag = userService.telIsFree(tel);
        if (!flag) {
            throw new TelRegistRepeatException(tel);
        }
        ControllerResultInfo result = new ControllerResultInfo();
        result.setData("ok");
        return new ResponseEntity<ControllerResultInfo>(result, HttpStatus.OK);
    }

    /**
    * 验证手机号码是否已经注册使用
    * @param appver 版本号
    * @param tel 手机号码
    * @param request 请求对象
    * @return ResponseEntity<ControllerResultInfo>
    */
    @RequestMapping(value = "/ns/{appver}/account/verifytelused/{tel}", method = RequestMethod.POST)
    public ResponseEntity<ControllerResultInfo> verifyTelUsed(
            @PathVariable("appver") @Regex(name = "appver", regexcontent = "vernum")String appver,
            @PathVariable("tel") @Regex(name = "tel", regexcontent = "tel")String tel,
            HttpServletRequest request) {
        boolean flag = userService.telIsFree(tel);
        if (flag) {
            throw new TelIsNotUsedException(tel);
        }
        ControllerResultInfo result = new ControllerResultInfo();
        result.setData("ok");
        return new ResponseEntity<ControllerResultInfo>(result, HttpStatus.OK);
    }

    /**
    * 验证码是否正确(正确了实现一次性登录)
    * @param appver 版本号
    * @param tel 手机号
    * @param checkcode 验证码
    * @param request 请求对象
    * @return ResponseEntity<ControllerResultInfo>
    */
    @RequestMapping(value = "/ns/{appver}/account/verifycheckcode/{tel}/{checkcode}", method = RequestMethod.POST)
    public ResponseEntity<ControllerResultInfo> verifycheckcode(
            @PathVariable("appver") @Regex(name = "appver", regexcontent = "vernum")String appver,
            @PathVariable("tel") String tel,
            @PathVariable("checkcode") String checkcode,
            HttpServletRequest request) {
        boolean flag = userService.telIsFree(tel);
        if (flag) {
            throw new TelIsNotUsedException(tel);
        }
        this.verifymsmcode(request, checkcode);
        VerificationCodeToken token = new VerificationCodeToken(tel, checkcode);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
        } catch (UnknownAccountException ex) {
            throw new com.vogue.supplymall.common.exception.IncorrectCredentialsException();
        }
        ControllerResultInfo result = new ControllerResultInfo();
        result.setData("ok");
        return new ResponseEntity<ControllerResultInfo>(result, HttpStatus.OK);
    }

    /**
     * 修改密码（一次性登录进入）
     * @param appver 版本号
     * @param dto 更新密码对象信息
     * @param request 请求对象
     * @return ResponseEntity<ControllerResultInfo>
     */
    @RequestMapping(value = "/ns/{appver}/account/updatepwd", method = RequestMethod.POST)
    public ResponseEntity<ControllerResultInfo> updatepwd(
            @PathVariable("appver") @Regex(name = "appver", regexcontent = "vernum")String appver,
            @Validated @RequestBody UpdatepwdDTO dto,
            HttpServletRequest request) {
        Subject subject = SecurityUtils.getSubject();
        if (subject != null && subject.getPrincipal() != null) {
            Object obj = subject.getPrincipal();
            if (obj != null) {
                UserInfo info = (UserInfo) obj;
                userService.updatepwd(Long.valueOf(info.getLoginId()), dto.getPassword());
                VerificationCodeRealm realmObj = (VerificationCodeRealm) SpringContextUtils.getBeanByClass(VerificationCodeRealm.class);
                if (realmObj != null) {
                    ((VerificationCodeRealm) realmObj).clearAllCache(new SimplePrincipalCollection(
                            AuthRealm.getCacheKey(info.getTel()), realmObj.getName()));
                }
                subject.logout();
                String msm = messageSourceUtils.getMessage("updatepwd.msm.success",
                        new Object[] {
                                VestUtils.getName()
                });
                try {
                    SMSUtils.sendMessage(info.getTel(), msm);
                } catch (Exception e) {
                    LOGGER_REGISTCONTROLLER.error("send msm is error:" + e.toString());
                }
            }
        } else {
            throw new NeedOnceLoginException();
        }
        ControllerResultInfo result = new ControllerResultInfo();
        result.setData("ok");
        return new ResponseEntity<ControllerResultInfo>(result, HttpStatus.OK);
    }

    /**
     * 修改密码（登录状态修改密码）
     * @param appver 版本号
     * @param dto 密码封装DTO
     * @param request 请求对象
     * @return ResponseEntity<ControllerResultInfo>
     */
    @RequestMapping(value = "/is/{appver}/account/updatepwd", method = RequestMethod.POST)
    public ResponseEntity<ControllerResultInfo> relupdatepwd(
            @PathVariable("appver") @Regex(name = "appver", regexcontent = "vernum")String appver,
            @Validated @RequestBody UpdatepwdDTO dto,
            HttpServletRequest request) {
        this.verifymsmcode(request, dto.getCheckCode());
        Subject subject = SecurityUtils.getSubject();
        Object obj = subject.getPrincipal();
        if (obj != null) {
            UserInfo info = (UserInfo) obj;
            userService.updatepwd(Long.valueOf(info.getLoginId()), dto.getPassword());

            AuthRealm authRealm = (AuthRealm) SpringContextUtils.getBeanByClass(
                    AuthRealm.class);
            if (authRealm != null) {
                authRealm.clearCache(new SimplePrincipalCollection(AuthRealm
                        .getCacheKey(info.getTel()), authRealm.getName()));
            }

            String msm = messageSourceUtils.getMessage("updatepwd.msm.success",
                    new Object[] {
                            VestUtils.getName()
            });
            try {
                SMSUtils.sendMessage(info.getTel(), msm);
            } catch (Exception e) {
                LOGGER_REGISTCONTROLLER.error("send msm is error:" + e.toString());
            }
        }
        ControllerResultInfo result = new ControllerResultInfo();
        result.setData("ok");
        return new ResponseEntity<ControllerResultInfo>(result, HttpStatus.OK);
    }

}
